﻿#pragma once

#ifndef PERFORMANCE_TEST
//#define PERFORMANCE_TEST
#endif

#include <d3d11.h>
#include <d3dcompiler.h>
#include <dxgi.h>
#include <intrin.h>

#include <thread>
#include <unordered_map>
#include <set>
#include <mutex>

#include "../Utils/Logger.h"
#include "../Utils/SkinUtil.h"

#include "../SDK/CBlockLegacy.h"
#include "../SDK/CCamera.h"
#include "../SDK/CChestBlockActor.h"
#include "../SDK/CGameMode.h"
#include "../SDK/CMinecraftUIRenderContext.h"
#include "../SDK/CMoveInputHandler.h"
#include "../SDK/CRakNetInstance.h"
#include "../SDK/CUIScene.h"
#include "../SDK/TextHolder.h"

#include "GameData.h"
#include "MinHook.h"

struct chatLogstructure {
	std::u8string name{};
	std::u8string message{};
};

class VMTHook;

class FuncHook {
private:
	void* funcPtr{};
	void* funcReal{};

private:
	// fast_io::freestanding::array<uint8_t, 10> funccall {
	//	0ui8,
	//	0ui8,
	//	0ui8,
	//	0ui8,
	//	0ui8,
	//	0xE9ui8,
	//	0ui8,
	//	0ui8,
	//	0ui8,
	//	0ui8
	// };

public:
	FuncHook() = default;

	void operator()(void* func, void* hooked) {
		funcPtr = func;
		auto ret = MH_CreateHook(func, hooked, &funcReal);
		if (ret == MH_OK && (__int64)func > 10) {
		} else
			Logger::LogC(LogGrade::warning, u8"MH_CreateHook = ", (int)ret);
		// fast_io::freestanding::my_memcpy(funccall.data(), func, 5);
		//*(uintptr_t*)&funccall[6] = (uintptr_t)func + 5;
		// fast_io::freestanding::array<uint8_t, 5> temp{0xE9ui8};
		//*(uintptr_t*)&temp[1] = (uintptr_t)hooked;
		// Utils::Utils::patchBytes(func, temp.data(), 5);
	}

	void operator()(uintptr_t func, void* hooked) {
		funcPtr = reinterpret_cast<void*>(func);
		auto ret = MH_CreateHook(funcPtr, hooked, &funcReal);
		if (ret == MH_OK && (__int64)func > 10) {
		} else
			Logger::LogC(LogGrade::warning, u8"MH_CreateHook = ", (int)ret);
		// fast_io::freestanding::my_memcpy(funccall.data(), funcPtr, 5);
		//*(uintptr_t*)&funccall[6] = (uintptr_t)func + 5;
		// fast_io::freestanding::array<uint8_t, 5> temp{0xE9ui8};
		//*(uintptr_t*)&temp[1] = (uintptr_t)hooked;
		// Utils::Utils::patchBytes(funcPtr, temp.data(), 5);
	}

	FuncHook(void* func, void* hooked) {
		funcPtr = func;
		auto ret = MH_CreateHook(func, hooked, &funcReal);
		if (ret == MH_OK && (__int64)func > 10) {
		} else
			Logger::LogC(LogGrade::warning, u8"MH_CreateHook = ", (int)ret);
		// fast_io::freestanding::my_memcpy(funccall.data(), func, 5);
		//*(uintptr_t*)&funccall[6] = (uintptr_t)func + 5;
		// fast_io::freestanding::array<uint8_t, 5> temp{0xE9ui8};
		//*(uintptr_t*)&temp[1] = (uintptr_t)hooked;
		// Utils::Utils::patchBytes(func, temp.data(), 5);
	};

	FuncHook(uintptr_t func, void* hooked) {
		funcPtr = reinterpret_cast<void*>(func);
		auto ret = MH_CreateHook(funcPtr, hooked, &funcReal);
		if (ret == MH_OK && (__int64)func > 10) {
		} else
			Logger::LogC(LogGrade::warning, u8"MH_CreateHook = ", (int)ret);
		// fast_io::freestanding::my_memcpy(funccall.data(), funcPtr, 5);
		//*(uintptr_t*)&funccall[6] = (uintptr_t)func + 5;
		// fast_io::freestanding::array<uint8_t, 5> temp{0xE9ui8};
		//*(uintptr_t*)&temp[1] = (uintptr_t)hooked;
		// Utils::Utils::patchBytes(funcPtr, temp.data(), 5);
	};

	~FuncHook() {
		Restore();
	}

	void Restore() {
		if (funcPtr != nullptr) [[likely]] {
			MH_DisableHook(funcPtr);
			// Utils::Utils::patchBytes(funcPtr, funccall.data(), 5);
		}
	}

	template <typename TRet, typename... TArgs>
	inline constexpr auto* GetFastcall() {
		using Fn = TRet(__fastcall*)(TArgs...);
		return reinterpret_cast<Fn>(funcReal);
	};
};

struct CoolSkinData {
	TextHolder unknown{};
	TextHolder unknown2{};
	TextHolder skinResourcePatch{};  // 0x040
	TextHolder geometryName{};       // 0x060 "geometry.humanoid.custom"
	uint8_t gap2[0x40]{};            // 0x080
	void* startAnimatedFrames{};     // 0x0C0
	void* endAnimatedFrames{};       // 0x0C8
	uint8_t gap3[0x8]{};             // 0x0D0
	TextHolder geometryData{};       // 0x0D8
	TextHolder skinAnimationData{};  // 0x0F8
	uint8_t gap4[0x20]{};            // 0x118
	bool isPremiumSkin{};            // 0x138
	bool isPersonaSkin{};
	bool isCapeOnClassicSkin{};
	void* startPersonaPieces{};
	void* endPersonaPieces{};
	uint8_t gap5[0x8]{};   // 0x150
	TextHolder armSize{};  // 0x158
	uint8_t gap6[0x8]{};   // 0x178
	void* startPieces{};
};

#ifdef _DEBUG
struct testVatble {  // only for test
public:
	uintptr_t** vTable{};  // 0x0000
};
#endif  // _DEBUG

class Hooks {
	friend class ICommand;
private:
	static bool shouldRender;

public:
	// char currentScreenName[100]{};

	static std::set<C_Entity*> entityList;
	static std::mutex entityList_mutex;

	static __int64 RMBManager;
	static int isThirdPerson;
	static bool shouldLocalPlayerBeImmobile;
	static bool isHUDHidden;
	static int tickCountNow;
	static bool isDigging;
	static std::u8string lastAutoCompleteStr;
	static bool isTicked;
	static fast_io::ip serverIp;
	// fast_io::unix_timestamp connecttime;

public:
	static void Init();
	static void Restore();
	static void Enable();

private:
	static bool ReturnTrue();
	static bool ReturnFalse();
	static void setPos(C_Entity* ent, vec3_t& poo);
	static void Actor_baseTick(C_Entity* _this);
	static void RMBManagerThingy(__int64 a1, __int64 a2);
	static void* Player_tickWorld(C_Player* _this, __int64);
	static void ClientInstanceScreenModel_sendChatMessage(void* _this, TextHolder* text);
	static void chatLogHookFunc(__int64 a1, TextHolder* msg, uint32_t a2);
	static __int64 UIScene_setupAndRender(C_UIScene* uiscene, __int64 screencontext);
	static __int64 UIScene_render(C_UIScene* uiscene, __int64 screencontext);
	static __int64 RenderText(__int64 a1, C_MinecraftUIRenderContext* renderCtx);
	static float* Dimension_getFogColor(__int64, float* color, __int64 brightness, float a4);
	static float Dimension_getTimeOfDay(__int64, int a2, float a3);
	static float Dimension_getSunIntensity(__int64, float a2, vec3_t* a3, float a4);
	static void ChestBlockActor_tick(C_ChestBlockActor*, void* a);
	static void Actor_lerpMotion(C_Entity* _this, vec3_t);
	static int AppPlatform_getGameEdition(__int64 _this);
	static void PleaseAutoComplete(__int64 _this, __int64 a2, TextHolder* text, int a4);
	static void LoopbackPacketSender_sendToServer(C_LoopbackPacketSender* a, C_Packet* packet);
	static float LevelRendererPlayer_getFov(__int64 _this, float a2, bool a3);
	static void MultiLevelPlayer_tick(C_EntityList* entityList);
	static void GameMode_startDestroyBlock(C_GameMode* _this, vec3_ti* a2, uint8_t face, void* a4, void* a5);
	static void GameMode_stopDestroyBlock(C_GameMode* _this, vec3_ti* a2);
	static void HIDController_keyMouse(C_HIDController* _this, void* a2, void* a3);
	static int BlockLegacy_getRenderLayer(C_BlockLegacy* a1);
	static __int8* BlockLegacy_getLightEmission(C_BlockLegacy* _this, __int8* a2);
	static __int64 LevelRenderer_renderLevel(__int64 _this, __int64 a2, __int64 a3);
	static void ClickFunc(__int64 a1, char a2, char a3, __int16 a4, __int16 a5, __int16 a6, __int16 a7, char a8);
	static __int64 MoveInputHandler_tick(C_MoveInputHandler* _this, C_Entity* a2);
	static __int64 ChestScreenController_tick(C_ChestScreenController* _this);
	static float GetGamma(uintptr_t* a1);
	static bool Actor_isInWater(C_Entity* _this);
	static void JumpPower(C_Entity* _this, float a2);
	static void Actor_ascendLadder(C_Entity* _this);
	static void Actor_swing(C_Entity* _this);
	static void Actor_startSwimming(C_Entity* _this);
	static void RakNetInstance_tick(C_RakNetInstance* _this, __int64 a2, __int64 a3);
	static float GameMode_getPickRange(C_GameMode* _this, __int64 a2, char a3);
	static __int64 GameMode_attack(C_GameMode* _this, C_Entity*);
	static __int64 ConnectionRequest_create(__int64 _this, __int64 privateKeyManager, void* a3, TextHolder* selfSignedId, TextHolder* serverAddress, __int64 clientRandomId, TextHolder* skinId, SkinData* skinData, __int64 capeData, CoolSkinData* coolSkinStuff, TextHolder* deviceId, int inputMode, int uiProfile, int guiScale, TextHolder* languageCode, bool sendEduModeParams, TextHolder* tenantId, __int64 unused, TextHolder* platformUserId, TextHolder* thirdPartyName, bool thirdPartyNameOnly, TextHolder* platformOnlineId, TextHolder* platformOfflineId, TextHolder* capeId);
	static bool DirectoryPackAccessStrategy__isTrusted(uintptr_t _this);
	static __int64 SkinRepository___loadSkinPack(__int64 _this, __int64 pack, __int64 a3);
	static GamerTextHolder* toStyledString(__int64 strIn, GamerTextHolder* strOut);
	static void MinecraftGame_onAppSuspended(__int64);
	static bool Mob__isImmobile(C_Entity*);
	static void Actor__setRot(C_Entity* _this, vec2_t& angle);
	static float getDestroySpeed(C_Player* _this, C_Block& block);
	static bool playerCallBack(C_Player* lp, __int64 a2, __int64 a3);
	static void InventoryTransactionManager__addAction(C_InventoryTransactionManager*, C_InventoryAction&);
	static void onActorDie(C_Entity*, __int64);
	static __int64 inventoryScreen__tick(C_CraftingScreenController* a1);
	static int ForceThirdPersonLol(__int64 a1);
	static void Actor__Destructor(C_Entity* ent);
	static int inputmode_Hook(C_Entity*);
	static std::u8string getEdition();

	static FuncHook setPosHook;
	static FuncHook Actor_baseTickHook;
	static FuncHook Player_tickWorldHook;
	static FuncHook ClientInstanceScreenModel_sendChatMessageHook;
	static FuncHook UIScene_setupAndRenderHook;
	static FuncHook UIScene_renderHook;
	static FuncHook RenderTextHook;
	static FuncHook inventoryScreen__tickHook;
	static FuncHook Dimension_getFogColorHook;
	static FuncHook Dimension_getTimeOfDayHook;
	static FuncHook Dimension_getSunIntensityHook;
	static FuncHook ChestBlockActor_tickHook;
	static FuncHook Actor_lerpMotionHook;
	static FuncHook playerCallBack_Hook;
	static FuncHook AppPlatform_getGameEditionHook;
	static FuncHook PleaseAutoCompleteHook;
	static FuncHook LoopbackPacketSender_sendToServerHook;
	static FuncHook LevelRendererPlayer_getFovHook;
	static FuncHook MultiLevelPlayer_tickHook;
	static FuncHook GameMode_startDestroyBlockHook;
	static FuncHook GameMode_stopDestroyBlockHook;
	static FuncHook HIDController_keyMouseHook;
	static FuncHook BlockLegacy_getRenderLayerHook;
	static FuncHook BlockLegacy_getLightEmissionHook;
	static FuncHook LevelRenderer_renderLevelHook;
	static FuncHook ClickFuncHook;
	static FuncHook MoveInputHandler_tickHook;
	static FuncHook ChestScreenController_tickHook;
	static FuncHook GetGammaHook;
	static FuncHook Actor_isInWaterHook;
	static FuncHook JumpPowerHook;
	static FuncHook RMBManagerThingyHook;
	static FuncHook MinecraftGame_onAppSuspendedHook;
	static FuncHook Actor_ascendLadderHook;
	static FuncHook Actor_swingHook;
	static FuncHook Actor_lookAtHook;
	static FuncHook Actor_startSwimmingHook;
	static FuncHook RakNetInstance_tickHook;
	static FuncHook GameMode_getPickRangeHook;
	static FuncHook GameMode_attackHook;
	static FuncHook ConnectionRequest_createHook;
	static FuncHook DirectoryPackAccessStrategy__isTrustedHook;
	static FuncHook SkinRepository___loadSkinPackHook;
	static FuncHook toStyledStringHook;
	static FuncHook Mob__isImmobileHook;
	static FuncHook Actor__setRotHook;
	static FuncHook getDestroySpeedHook;
	static FuncHook InventoryTransactionManager__addActionHook;
	static FuncHook actorDieHook;
	static FuncHook ChatLogHook;
	static FuncHook forceThirdPersonHook;
	static FuncHook Actor__DestructorHook;
	static FuncHook play_inputmodeHook;
	static FuncHook getEditionHook;

	static FuncHook lambdaHooks;
};

